#include <iostream>
#include "task.hpp"
#include <string>
#include <vector>
#include <unistd.h>
#include <ctime>

using namespace std;

enum
{
    UsageError = 1,
    ArgError,
    PipeError
};

void Usage(const string& proc)  // ask for how many process will be created
{
    cout << "Usage: " << proc << " subprocess_num" << endl;
}

class Channel   // for writing to pipe
{
public:
    Channel(int wfd, pid_t sub_process_id, const string& name):
        m_wfd(wfd), m_sub_process_id(sub_process_id), m_name(name){}

    void printDebugDemonstration()const
    {
        cout << "wfd: " << m_wfd
            << ", subprocess_id: " << m_sub_process_id
            << ", name: " << m_name << endl;
    }
    const string& get_name()const
    {
        return m_name;
    }
    int get_wfd()const
    {
        return m_wfd;
    }
    pid_t get_pid()const
    {
        return m_sub_process_id;
    }

private:
    int m_wfd;      // the entrance id of pipe
    pid_t m_sub_process_id; // pid
    string m_name;  // the message of channel-self
};

class ProcessPool
{
public:
    ProcessPool(size_t process_num):m_channel_num(process_num){}

    int CreateProcess(work_t work)  // utilizing callback_function
    {
        for(size_t i = 0; i < m_channel_num; ++i)
        {
            int pipefd[2]{0};
            int n = pipe(pipefd);
            if(n < 0) {return PipeError;}

            pid_t id = fork();
            if(id == 0)
            {
                // child process -- r
                close(pipefd[1]);
                // run task
                worker(pipefd[0]);
                exit(0);
            }
            // father process -- w
            close(pipefd[0]);
            string channel_name = "channel-" + to_string(i);
            channels.push_back(Channel(pipefd[1], id, channel_name));
        }
        return 0;
    }

    int NextChannel()const
    {
        static int next = 0;
        int c = next;
        next++;
        next %= channels.size();
        return c;
    }

    void SendTaskCode(int index, uint32_t code)const
    {
        cout << "send code: "<< code << " to " << channels[index].get_name() << " subprocess id: " << channels[index].get_pid() << endl;
        write(channels[index].get_wfd(), &code, sizeof(code));
    }

    void Debug()const
    {
        for(const auto& channel: channels)
        {
            channel.printDebugDemonstration();
        }
    }

private:
    size_t m_channel_num;
    vector<Channel> channels;
};



// ./a.out 5
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return UsageError;
    }
    int sub_process_num = std::stoi(argv[1]);
    if (sub_process_num <= 0)
        return ArgError;

    srand((uint64_t)time(nullptr));

    // 1. 创建通信信道和子进程 -- bug
    ProcessPool *processpool_ptr = new ProcessPool(sub_process_num);
    processpool_ptr->CreateProcess(worker);
    // processpool_ptr->Debug();

    // 2. 控制子进程
    while(true)
    {
        // a. 选择一个进程和通道
        int channel = processpool_ptr->NextChannel();
        // cout << channel.name() << endl;

        // b. 你要选择一个任务
        uint32_t code = NextTask();

        // c. 发送任务
        processpool_ptr->SendTaskCode(channel, code);

        sleep(1);
    }

    sleep(100);

    // 3. 回收子进程
    // wait sub process;

    delete processpool_ptr;
    return 0;
}